package com.cooper.mediadb.online;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import android.content.Context;
import android.content.res.AssetManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Environment;
import android.util.Log;

import com.cooper.android.comm.FileUtils;
import com.cooper.scraper.DownloadException;
import com.cooper.scraper.DownloadParams;
import com.cooper.scraper.DownloadPublishRunner;
import com.cooper.scraper.HttpDownload;
import com.cooper.scraper.ResourceCollector;
import com.cooper.scraper.ResourceScraper;
import com.cooper.scraper.ResourceScraperRunner;
import com.cooper.scraper.ResultUrl;
import com.cooper.scraper.RunnerThread;
import com.cooper.scraper.ScraperException;

public class OnlineMediaScrapeRunner extends DownloadPublishRunner implements
		ResourceScraperRunner<OnlineMedia> {

	// private static OnlineMediaScrapeRunner instance = null;

	// public static void initConfigure(DownloadParams params) {
	// instance = new OnlineMediaScrapeRunner(params);
	// }

	// public static OnlineMediaScrapeRunner getInstance() {
	// if (instance == null) {
	// instance = new OnlineMediaScrapeRunner();
	// }
	// return instance;
	// }

	// public static void destroyInstance() {
	// if (instance != null) {
	// instance.destroy();
	// }
	// }

	private static final boolean DEBUG = false;

	private static final long UPDATE_TIME_LONG = 1 * 24 * 60 * 60 * 1000;

	private static final String ASSET_PATH = "scraper";

	private static final String SCAPER_STORE_DIR = ".cooper_soft/scapers/";

	private Context context;

	public OnlineMediaScrapeRunner(Context context, DownloadParams params) {
		super(params);
		this.context = context;
	}

	public OnlineMediaScrapeRunner(Context context) {
		super();
		this.context = context;
	}

	public void listResource(ResourceCollector<OnlineMedia> resultMedia)
			throws ScraperException {
		run(resultMedia.generateKey(), new DownloadResultMedia(params,
				resultMedia));
	}

	class DownloadResultMedia extends RunnerThread {

		private ResourceCollector<OnlineMedia> resultMedias;

		public DownloadResultMedia(DownloadParams params,
				ResourceCollector<OnlineMedia> resultMedias) {
			super(params);
			this.resultMedias = resultMedias;
		}

		@Override
		public void run() {
			super.run();
			try {
				if (!resultMedias.ready()){
					resultMedias.setScraper(getScraper(resultMedias.getScraperId()));
				}
				
				
				ResultUrl resultUrl = resultMedias.scraperListUrl();

				String redirectUrl = httpDownload.getRedirectUrl(resultUrl
						.getUrl());

				boolean redirect = false;
				if (!redirectUrl.equals(resultUrl.getUrl())) {
					resultUrl.setUrl(redirectUrl);
					redirect = true;
				}

				String page = httpDownload.downloadPage(resultUrl.getUrl(),
						resultUrl.getEncodingType(), false);
				if (!Thread.currentThread().isInterrupted()) {
					if (redirect) {
						resultMedias.scraperResult(page, resultUrl.getUrl(),
								redirectUrl);
					} else
						resultMedias.scraperResult(page, resultUrl.getUrl());
				}
				complete(resultMedias.generateKey(), resultMedias);
			} catch (DownloadException e) {
				fail(resultMedias.generateKey(), e.getErrorCode());
			} catch (ScraperException e) {
				fail(resultMedias.generateKey(), e.getErrorCode());
			} catch (Exception e) {
				Log.e("DownloadResultMovies.run", "result:" + resultMedias
						+ "resultUrl:", e);
				fail(resultMedias.generateKey(), DownloadException.ERROR_OTHER);
			}

		}
	}

	public void getResourceDetails(String scraperId, OnlineMedia media) {
		run(media.generateSubscribedKey(), new DownloadMediaDetails(params,
				scraperId, media));
	}

	class DownloadMediaDetails extends RunnerThread {

		private OnlineMedia movie;

		//private ResourceScraper<OnlineMedia> scraper;
		private String scraperId;
		
		public DownloadMediaDetails(DownloadParams params,
				String scraperId, OnlineMedia movie) {
			super(params);
			this.scraperId = scraperId;
			this.movie = movie;
		}

		@Override
		public void run() {
			super.run();
			try {
				ResourceScraper<OnlineMedia> scraper = getScraper(scraperId);
				
				String page = httpDownload.downloadPage(movie.getDetailsUrl(),
						movie.getDetailsPageEncodeType());
				complete(movie.generateSubscribedKey(),
						scraper.extractDetails(page, movie.getId()));
			} catch (DownloadException e) {
				fail(movie.generateSubscribedKey(), e.getErrorCode());
			} catch (ScraperException e) {
				fail(movie.generateSubscribedKey(), e.getErrorCode());
			} catch (Exception e) {
				Log.e("DownloadMediaDetails.run", "scraper:" + scraperId
						+ "result:" + movie.getTitle() + "resultUrl:", e);
				fail(movie.generateSubscribedKey(),
						DownloadException.ERROR_OTHER);
			}
		}
	}

	public void analyzeMediaUrl(Context context, MediaSource sources,
			String format) {
		run(sources.getUrl(), new AnalyzeVideoThread(params, sources, format));
	}

	private Map<String, String> scrapers = new HashMap<String, String>();

	private synchronized OnlineMediaScraper getScraper(String scraperId)
			throws ScraperException {
		String result = scrapers.get(scraperId);

		if (result == null || "".equals(result.trim())) {

			String storeDir = Environment.getExternalStorageDirectory()
					.toString() + "/" + SCAPER_STORE_DIR + "/";
			File storeDirFile = new File(storeDir);
			if (!storeDirFile.exists() || !storeDirFile.isDirectory()) {
				storeDirFile.mkdirs();
			}

			if (params.isCancelled()) {
				return null;
			}
			String fileName;

			Matcher m = Pattern.compile("([^\\/\\s\\.]+?\\.xml)[^\\/]*$")
					.matcher(scraperId);
			if (m.find()) {
				fileName = m.group(1);
			} else {
				fileName = FileUtils.stringToFileName(scraperId);
			}
			if (!DEBUG) {

				File scraperFile = new File(storeDir + fileName);
				if (scraperFile.exists()
						&& ((new Date().getTime() - scraperFile.lastModified()) < UPDATE_TIME_LONG)) {
					try {
						result = FileUtils.readTextFile(scraperFile
								.getAbsolutePath());
						Log.d("ScraperDownTask", "load from local file - "
								+ scraperId);
					} catch (Exception e) {
						Log.e("ScraperDownTask", e.getMessage(), e);
					}
				}
				if (result == null || "".equals(result.trim())) {
					NetworkInfo networkInfo = ((ConnectivityManager) context
							.getSystemService(Context.CONNECTIVITY_SERVICE))
							.getActiveNetworkInfo();
					if ((networkInfo != null)
							&& (NetworkInfo.State.CONNECTED == networkInfo
									.getState())
							&& (!params.isOnlyWIFI() || (networkInfo.getType() == ConnectivityManager.TYPE_WIFI))
							&& (Environment.getExternalStorageState()
									.equals(Environment.MEDIA_MOUNTED))) {


						if (params.isCancelled()) {
							return null;
						}
						try {
							HttpDownload httpDownload = new HttpDownload(params);

							result = httpDownload.downloadPage(scraperId, false);
						
							Log.d("ScraperDownTask", "load from internet - "
									+ scraperId);
							try {
								if (scraperFile.exists()) {
									scraperFile.delete();
								}
								FileUtils.writerTextFile(
										scraperFile.getAbsolutePath(), result);
							} catch (Exception e) {
								Log.e("ScraperDownTask", e.getMessage(), e);
							}

						} catch (Exception e) {
							Log.e("ScraperDownTask", e.getMessage(), e);
						}
					}
				}
			}
			if (params.isCancelled()) {
				return null;
			}
			if (result == null || "".equals(result.trim())) {
			
			AssetManager am = context.getAssets();
			try {
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(am.open(ASSET_PATH + "/"
								+ fileName)));
				try {
					StringBuffer scraperTxt = new StringBuffer();
					String line = reader.readLine();
					while (line != null) {
						scraperTxt.append(line);
						scraperTxt.append("\n");
						line = reader.readLine();
					}
					result = scraperTxt.toString();
					Log.d("ScraperDownTask", "load from assets - " + scraperId);
				} finally {
					reader.close();
				}
			} catch (Exception e) {
				Log.e("ScraperDownTask", fileName + "|" + scraperId, e);
			}
			}
			scrapers.put(scraperId, result);
		}

		if (result != null && !"".equals(result.trim())) {
			// TODO getScraperParam for db

			return new OnlineMediaScraper(scraperId, result,
					new HashMap<String, String>(0), params);
		} else
			throw new ScraperException();
	}

}
